一起来学C++:C++中的代码重用 您所在的位置:网站首页 cpp using 一起来学C++:C++中的代码重用

一起来学C++:C++中的代码重用

2023-04-12 23:04| 来源: 网络整理| 查看: 265

本章内容包括:

has-a关系;包含对象成员的类;模板类valarray;私有和保护继承;多重继承;虚基类;创建类模板;使用类模板;模板的具体化。

C++的一个主要目标是促进代码重用。公有继承是实现这种目标的机制之一,但并不是唯一的机制。本章将介绍其他方法,其中之一是使用这样的类成员:本身是另一个类的对象。这种方法称为包含(containment)、组合(composition)或层次化(layering)。另一种方法是使用私有或保护继承。通常,包含、私有继承和保护继承用于实现has-a关系,即新的类将包含另一个类的对象。例如,HomeTheater类可能包含一个BluRayPlayer对象。多重继承使得能够使用两个或更多的基类派生出新的类,将基类的功能组合在一起。

第10章介绍了函数模板,本章将介绍类模板——另一种重用代码的方法。类模板使我们能够使用通用术语定义类,然后使用模板来创建针对特定类型定义的特殊类。例如,可以定义一个通用的栈模板,然后使用该模板创建一个用于表示int值栈的类和一个用于表示double值栈的类,甚至可以创建一个这样的类,即用于表示由栈组成的栈。

14.1 包含对象成员的类

首先介绍包含对象成员的类。有一些类(如string类和第16章将介绍的标准C++类模板)为表示类中的组件提供了方便的途径。下面来看一个具体的例子。

学生是什么?入学者?参加研究的人?残酷现实社会的避难者?有姓名和一系列考试分数的人?显然,最后一个定义完全没有表示出人的特征,但非常适合于简单的计算机表示。因此,让我们根据该定义来开发Student类。

将学生简化成姓名和一组考试分数后,可以使用一个包含两个成员的类来表示它:一个成员用于表示姓名,另一个成员用于表示分数。对于姓名,可以使用字符数组来表示,但这将限制姓名的长度。当然,也可以使用char指针和动态内存分配,但正如第12章指出的,这将要求提供大量的支持代码。一种更好的方法是,使用一个由他人开发好的类的对象来表示。例如,可以使用一个String类(参见第12章)或标准C++ string类的对象来表示姓名。较简单的选择是使用string类,因为C++库提供了这个类的所有实现代码,且其实现更完美。要使用String类,您必须在项目中包含实现文件string1.cpp。

对于考试分数,存在类似的选择。可以使用一个定长数组,这限制了数组的长度;可以使用动态内存分配并提供大量的支持代码;也可以设计一个使用动态内存分配的类来表示该数组;还可以在标准C++库中查找一个能够表示这种数据的类。

自己开发这样的类一点问题也没有。开发简单的版本并不那么难,因为double数组与char数组有很多相似之处,因此可以根据String类来设计表示double数组的类。事实上,本书以前的版本就这样做过。

当然,如果C++库提供了合适的类,实现起来将更简单。C++库确实提供了一个这样的类,它就是valarray。

14.1.1 valarray类简介

valarray类是由头文件valarray支持的。顾名思义,这个类用于处理数值(或具有类似特性的类),它支持诸如将数组中所有元素的值相加以及在数组中找出最大和最小的值等操作。valarray被定义为一个模板类,以便能够处理不同的数据类型。本章后面将介绍如何定义模板类,但就现在而言,您只需知道如何使用模板类即可。

模板特性意味着声明对象时,必须指定具体的数据类型。因此,使用valarray类来声明一个对象时,需要在标识符valarray后面加上一对尖括号,并在其中包含所需的数据类型:

valarray q_values; // an array of int valarray weights; // an array of double

第4章介绍vector和array类时,您见过这种语法,它非常简单。这些类也可用于存储数字,但它们提供的算术支持没有valarray多。

这是您需要学习的唯一新语法,它非常简单。

类特性意味着要使用valarray对象,需要了解这个类的构造函数和其他类方法。下面是几个使用其构造函数的例子:

double gpa[5] = {3.1, 3.5, 3.8, 2.9, 3.3}; valarray v1; // an array of double, size 0 valarray v2(8); // an array of 8 int elements valarray v3(10,8); // an array of 8 int elements, // each set to 10 valarray v4(gpa, 4); // an array of 4 elements // initialized to the first 4 elements of gpa

从中可知,可以创建长度为零的空数组、指定长度的空数组、所有元素度被初始化为指定值的数组、用常规数组中的值进行初始化的数组。在C++11中,也可使用初始化列表:

valarray v5 = {20, 32, 17, 9}; // C++11

下面是这个类的一些方法。

operator :让您能够访问各个元素。size():返回包含的元素数。sum():返回所有元素的总和。max():返回最大的元素。min():返回最小的元素。

还有很多其他的方法,其中的一些将在第16章介绍;但就这个例子而言,上述方法足够了。

14.1.2 Student类的设计

至此,已经确定了Student类的设计计划:使用一个string对象来表示姓名,使用一个valarray来表示考试分数。那么如何设计呢?您可能想以公有的方式从这两个类派生出Student类,这将是多重公有继承,C++允许这样做,但在这里并不合适,因为学生与这些类之间的关系不是is-a模型。学生不是姓名,也不是一组考试成绩。这里的关系是has-a,学生有姓名,也有一组考试分数。通常,用于建立has-a关系的C++技术是组合(包含),即创建一个包含其他类对象的类。例如,可以将Student类声明为如下所示:

class Student { private: string name; // use a string object for name valarray scores; // use a valarray object for scores ... };

同样,上述类将数据成员声明为私有的。这意味着Student类的成员函数可以使用string和valarray类的公有接口来访问和修改name和scores对象,但在类的外面不能这样做,而只能通过Student类的公有接口访问name和score(请参见图14.1)。对于这种情况,通常被描述为Student类获得了其成员对象的实现,但没有继承接口。例如,Student对象使用string的实现,而不是char * name或char name [26]实现来保存姓名。但Student对象并不是天生就有使用函数string operator+=()的能力。

图14.1 对象中的对象:包含

接口和实现

使用公有继承时,类可以继承接口,可能还有实现(基类的纯虚函数提供接口,但不提供实现)。获得接口是is-a关系的组成部分。而使用组合,类可以获得实现,但不能获得接口。不继承接口是has-a关系的组成部分。

对于has-a关系来说,类对象不能自动获得被包含对象的接口是一件好事。例如,string类将+运算符重载为将两个字符串连接起来;但从概念上说,将两个Student对象串接起来是没有意义的。这也是这里不使用公有继承的原因之一。另一方面,被包含的类的接口部分对新类来说可能是有意义的。例如,可能希望使用string接口中的operator= 0 and < "

本书在介绍C++特性的同时,还讨论了基本C语言,使两者成为有机的整体。书中介绍了C++的基本概念,并通过短小精悍的程序来阐明,这些程序都很容易复制和试验。书中还介绍了输入和输出,如何让程序执行重复性任务,如何让程序做出选择,处理数据的多种方式,以及如何使用函数等内容。另外,本书还讲述了C++在C语言的基础上新增的很多特性,包括:

类和对象;继承;多态、虚函数和RTTI(运行阶段类型识别);函数重载;引用变量;泛型(独立于类型的)编程,这种技术是由模板和标准模板库(STL)提供的;

 处理错误条件的异常机制;

管理函数、类和变量名的名称空间。


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有